package org.liuh.designs.spider;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.liuh.designs.spider.dtos.AddressNode;
import org.liuh.designs.spider.utils.HttpClientUtil;
import org.liuh.designs.spider.utils.RandomUtils;
import org.liuh.designs.spider.utils.SpiderHttpUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @ClassName: AreaUtils
 * @Description:
 * @Author: liuh
 * @Date: 2020/9/29 17:32
 * @Version: 1.0
 */
public class AreaConstant {

    // 我擦，出现并发问题了！！！！！擦擦擦擦擦丢..
//    public static StringBuilder sb = new StringBuilder();

    public static final String RDS_PROVINCE_KEY = "key_province_json_data";
    public static final String RDS_CITY_KEY = "key_city_json_data";
    public static final String RDS_COUNTY_KEY = "key_county_json_data";
    public static final String RDS_TOWN_KEY = "key_town_json_data";

    public static final String RDS_WAIT_DEAL_TOWN_KEY_ = "wait_deal_town_list_";


    // 国家统计局. host
    public static final String HOST = "http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/";
    // 首页地址..
    public static final String HOME_PAGE = "http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2019/index.html?t=%s";

    /**
     * @Description: 省级区域后缀..如北京11： 110000000000
     * @Author: liuh
     * @Date: 2020/9/29
     */
    public static final String AREA_PREFIX = "%s0000000000";

    /**
     * 中国..
     */
    public static final String CHINA_AREA_CODE = "100000000000";
    public static final String CHINA_NAME = "中华人民共和国";

    /**
     * @Description: 国家统计局编码; gb2312
     * @Author: liuh
     * @Date: 2020/9/29
     */
    public static final String CHAR_SET = "gb2312";

    /**
     * 数字分隔符..
     */
    public static final String SPLIT_SUFFIX = ".html";

    /**
     * @Description: 获取待处理key..
     * @Author: liuh
     * @Date: 2020/10/13
     */
    public static String getWaitKey() {
        // TODO. 后期如果改了一次 + 1
        return RDS_WAIT_DEAL_TOWN_KEY_;
    }

    @Getter
    public enum ClassEnum {
        province,
        city,
        county,
        town,
        village,
        ;
    }

    @Getter
    public enum TagEnum {
        table, tr, head, td, a,
        ;
    }

    @Getter
    public enum AttrEnum {
        href,
        ;
    }

    @Getter
    public enum HttpUtilEnum {
        HTTP_CLIENT, NORMAL;
    }

    @Getter
    @AllArgsConstructor
    public enum LevelEnum {
        LEVEL_0(0, "国家"),
        LEVEL_1(1, "省"),
        LEVEL_2(2, "市"),
        LEVEL_3(3, "区/县"),
        LEVEL_4(4, "城镇/街道"),
        ;
        private int level;
        private String desc;
    }


    /**
     * @Description:
     * @Author: liuh
     * @Date: 2020/9/29
     */
    public static String getNameByClass(ClassEnum classEnum, TagEnum tagEnum) {
        return classEnum.name() + tagEnum.name();
    }


    /**
     * @Description: 获取中国节点..
     * @Author: liuh
     * @Date: 2020/9/30
     */
    public static AddressNode getRootNode(HttpUtilEnum type) {
        AddressNode china = new AddressNode(null, AreaConstant.CHINA_NAME, AreaConstant.CHINA_AREA_CODE, AreaConstant.HOME_PAGE, null, LevelEnum.LEVEL_0.getLevel(), null);
        String result = null;
        String random = RandomUtils.generateNumberString(4);
        if (type == HttpUtilEnum.NORMAL) {
            // 第一步： 获取首页，省份信息..
            result = SpiderHttpUtils.sendGet(false, String.format(AreaConstant.HOME_PAGE, random), null, null, AreaConstant.CHAR_SET);
        } else if (type == HttpUtilEnum.HTTP_CLIENT) {
            result = HttpClientUtil.doHttpGet(String.format(AreaConstant.HOME_PAGE, random), null, null, AreaConstant.CHAR_SET);
        }
        if (result == null) {
            return null;
        }
        // 第二步： 获取省份..
        List<AddressNode> provinceNodeList = new ArrayList<>();
        AddressNode addressNode;
        Document provincePage = Jsoup.parse(result);
        if (provincePage == null) {
            return null;
        }
        Elements provinceTables = provincePage.getElementsByClass(AreaConstant.getNameByClass(AreaConstant.ClassEnum.province, AreaConstant.TagEnum.table));
        if (provinceTables == null || provinceTables.isEmpty()) {
            return null;
        }
        Elements provinceTrs = provinceTables.first().getElementsByClass(AreaConstant.getNameByClass(ClassEnum.province, TagEnum.tr));
        if (provinceTrs == null || provinceTrs.isEmpty()) {
            return null;
        }
        for (Element provinceTr : provinceTrs) {
            Elements provincesTds = provinceTr.getElementsByTag(AreaConstant.TagEnum.td.name());
            Iterator<Element> iterator = provincesTds.iterator();
            while (iterator.hasNext()) {
                Element next = iterator.next();
                if (next != null) {
                    Elements provinceLinkTag = next.getElementsByTag(AreaConstant.TagEnum.a.name());
                    String provinceName = provinceLinkTag.text();
                    if (provinceName == null || provinceName.isEmpty()) {
                        // 无数据..
                        continue;
                    }
                    String linkUrl = provinceLinkTag.attr(AreaConstant.AttrEnum.href.name());
                    //获取省份
                    addressNode = new AddressNode();
                    addressNode.setParentNode(china);
                    addressNode.setAddressName(provinceName);
                    addressNode.setAddressCode(convertProvinceCode(linkUrl));
                    addressNode.setLevel(LevelEnum.LEVEL_1.getLevel());
                    addressNode.setNodeUrl(getFullLinkUrl(AreaConstant.HOST, linkUrl, AreaConstant.ClassEnum.province));
                    provinceNodeList.add(addressNode);
                }
            }
        }
        china.setChildNodeList(provinceNodeList);
        return china;
    }

    /**
     * @Description: 根据地质返回全量
     * @Author: liuh
     * @Date: 2020/9/30
     */
    public static String getFullLinkUrl(String parentUrl, String href, AreaConstant.ClassEnum classEnum) {
        StringBuilder sb = new StringBuilder();
        switch (classEnum) {
            case province:
            case city:
                sb.setLength(0);
                sb.append(parentUrl);
                sb.append(href);
                return sb.toString();
            case county:
            case town:
                sb.setLength(0);
                String moduleHref = parentUrl.substring(0, parentUrl.lastIndexOf("/") + 1);
                sb.append(moduleHref);
                sb.append(href);
                return sb.toString();
        }
        return null;
    }

    /**
     * @Description: 转化省份地址..
     * @Author: liuh
     * @Date: 2020/9/29
     */
    public static String convertProvinceCode(String url) {
        return String.format(AreaConstant.AREA_PREFIX, url.replace(AreaConstant.SPLIT_SUFFIX, ""));
    }

    /**
     * @Description: 将数据保存到json文件中..
     * @Author: liuh
     * @Date: 2020/10/10
     */
    public static boolean createJsonFile(Object jsonData, String filePath) {
        String content = JSON.toJSONString(jsonData, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
        // 标记文件生成是否成功
        boolean flag = true;
        // 生成json格式文件
        try {
            // 保证创建一个新文件
            File file = new File(filePath);
            if (!file.getParentFile().exists()) { // 如果父目录不存在，创建父目录
                file.getParentFile().mkdirs();
            }
            if (file.exists()) {
                file.delete();
            }
            file.createNewFile();
            // 将格式化后的字符串写入文件
            Writer write = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            write.write(content);
            write.flush();
            write.close();
        } catch (Exception e) {
            flag = false;
            e.printStackTrace();
        }
        return flag;
    }

}
